<template>
  <div>
    <el-select
      v-model="displayValue"
      :multiple="multiple"
      placeholder=""
      filterable
      remote
      clearable
      :key="key"
      ref="select"
      @focus="onSelectFocus"
    ></el-select>
    <el-dialog :visible.sync="showDialog" :title="title" @opened="onDlgOpened">
      <el-tree
        :data="treeData"
        :props="defaultProps"
        :show-checkbox="multiple"
        node-key="id"
        ref="tree"
        highlight-current
        :default-expanded-keys="defaultExpandedKeys"
        :current-node-key="currentNodeKey"
        @node-click="onNodeClick"
      ></el-tree>
      <span slot="footer" class="dialog-footer">
        <el-row type="flex" justify="center">
          <el-button @click="onClickDlgNo" size="small">取 消</el-button>
          <el-button type="primary" @click="onClickDlgYes" size="small">确 定</el-button>
        </el-row>
      </span>
    </el-dialog>
  </div>
</template>

<script>
// import findTree from 'xe-utils/findTree'
import eachTree from 'xe-utils/eachTree'
import searchTree from 'xe-utils/searchTree'
// import mapTree from 'xe-utils/mapTree'
import filterTree from 'xe-utils/filterTree'
// import toTreeArray from 'xe-utils/toTreeArray'

const demoData = [
  {
    id: 1,
    label: '一级 1',
    children: [
      {
        id: 4,
        label: '二级 1-1',
        children: [
          {
            id: 9,
            label: '三级 1-1-1',
          },
          {
            id: 10,
            label: '三级 1-1-2',
          },
        ],
      },
    ],
  },
  {
    id: 2,
    label: '一级 2',
    children: [
      {
        id: 5,
        label: '二级 2-1',
      },
      {
        id: 6,
        label: '二级 2-2',
      },
    ],
  },
  {
    id: 3,
    label: '一级 3',
    children: [
      {
        id: 7,
        label: '二级 3-1',
      },
      {
        id: 8,
        label: '二级 3-2',
      },
    ],
  },
]

const type = (o) => {
  const s = Object.prototype.toString.call(o)
  return s.match(/\[object (.*?)\]/)[1].toLowerCase()
}

const treeToArray = function (obj) {
  const stack = [] // 声明栈，用来存储待处理元素
  const res = [] // 接收结果
  stack.push(obj) // 将初始元素压入栈
  while (stack.length) {
    // 栈不为空则循环执行
    const item = stack[0] // 取出栈顶元素
    res.push(item) // 元素本身压入结果数组
    stack.shift() // 将当前元素弹出栈
    // 逻辑处理，如果当前元素包含子元素，则将子元素压入栈
    if (item.children && item.children.length) {
      stack.push(...item.children)
    }
  }
  return res
}

export default {
  data() {
    return {
      key: null,
      inheritAttrs: false,
      displayValue: this.multiple ? [] : '',
      showDialog: false,
      treeData: null,
      defaultProps: {
        children: 'children',
        label: 'label',
      },
      pickedValue: null,
      needUpdate: true,
    }
  },
  props: {
    title: {
      type: String,
      default() {
        return ''
      },
    },
    multiple: {
      type: Boolean,
      default() {
        return false
      },
    },
    bindedValue: { type: [String, Array], required: true },
    defaultExpandedKeys: {
      type: Array,
      default() {
        return []
      },
    },
    // currentNodeKey: { type: String },
  },
  model: {
    prop: 'bindedValue',
    event: 'save',
  },
  computed: {
    currentNodeKey() {
      if (type(this.bindedValue) === 'string') {
        if (type(this.treeData[0].id) === 'string') {
          return this.bindedValue
        } else {
          return Number(this.bindedValue)
        }
      } else {
        return undefined
      }
    },
  },
  watch: {
    bindedValue: {
      handler: function (newVal, oldVal) {
        this.needUpdate = true
        // this.existedCheck()
        this.key = Math.random()
        this.updatePicked()
        // this.$nextTick(() => {
        //   this.updateDisplayValue()
        //   this.needUpdate = false
        // })
        this.updateDisplayValue()
        this.needUpdate = false
      },
      // immediate: true,
    },
  },
  created() {
    // console.log('bindedValue', this.bindedValue)
    this.treeData = demoData
    this.existedCheck()
    this.updateDisplayValue()
  },
  mounted() {
    // this.init()
    // console.log('bindedValue', this.bindedValue)
    // this.updateDisplayValue()
  },
  methods: {
    init() {
      this.updatePicked()
    },
    updateDisplayValue() {
      // this.$refs.select.$el.querySelector('.el-input__inner').value = ''
      console.log('this.bindedValue', this.bindedValue)
      // const list = toTreeArray(this.treeData)
      let list = []
      this.treeData.forEach((item) => {
        list = list.concat(treeToArray(item))
      })
      console.log('listttt', list)
      const bv = this.bindedValue
      if (type(bv) === 'string') {
        const display = filterTree(this.treeData, (item) => {
          return String(item.id) === bv
        })
        // const list = [
        //   { id: 1, label: 'yifefef' },
        //   { id: 2, label: 'efefer' },
        //   { id: 3, label: 'safefefen' },
        // ]
        // const display = list.filter((item) => {
        //   return String(item.id) === bv
        // })
        console.log('string display', display, display[0].label)
        this.displayValue = display[0].label
        // this.$set(this, 'displayValue', display[0].label)
        console.log('this.bindedValue after', this.bindedValue)
      } else {
        const list = this.bindedValue.map((val) => {
          let display
          eachTree(this.treeData, (item) => {
            if (String(item.id) === val) {
              display = item.label
            }
          })
          return display
        })
        this.displayValue = list
        // this.$set(this, 'displayValue', ['1', '4'])
      }
      // this.displayValue = this.bindedValue
    },
    existedCheck() {
      const bv = this.bindedValue
      if (this.treeData.length > 0 && (bv === '' || bv === [])) return
      const result = searchTree(this.treeData, (item) => {
        if (type(bv) === 'string') {
          return String(item.id) === bv
        } else {
          return bv.some((ele) => {
            if (type(ele) === 'string') {
              return String(item.id) === ele
            } else {
              throw new Error('数组里必须是字符串')
            }
          })
        }
      })
      console.log('result', result)
      if (result.length === 0) {
        console.error('传入组件的v-model有误')
      } else {
        if (type(bv) === 'array') {
          if (result.length !== bv.length) {
            console.error('传入组件的v-model有误')
          }
        }
      }
    },
    updatePicked() {
      // null undefined '' 0 [] {}setCurrentKey(null)
      if (!this.needUpdate) return
      console.log(this.bindedValue)
      if (!this.bindedValue) {
        // null undefined '' 0 的情形
        this.clearCurrent()
        this.displayValue = ''
        return
      }
      const list = ['string', 'number']
      const t = type(this.bindedValue)
      if (list.includes(t)) {
        console.log('jiben')
        this.$refs.tree && this.$refs.tree.setCurrentKey(this.bindedValue)
      } else {
        if (t === 'array') {
          if (this.bindedValue.length === 0) {
            this.clearCurrent()
            this.displayValue = ''
            return
          }
          console.log('arr')
        } else if (t === 'object') {
          // 暂时不处理对象类型，就先这么放着吧
          console.log('obj')
          if (Object.getOwnPropertyNames(this.bindedValue).length === 1) {
            this.clearCurrent()
            return
          }
          this.$refs.tree && this.$refs.tree.setCurrentNode(this.bindedValue)
          this.displayValue = this.bindedValue.label
        } else {
          console.error('no!')
        }
      }
    },
    clearCurrent() {
      this.$refs.tree && this.$refs.tree.setCurrentKey(null)
    },
    onDlgOpened() {
      // this.updatePicked()
      // this.needUpdate = false
    },
    onSelectFocus() {
      this.showDialog = true
    },
    onNodeClick(data, node) {
      // this.pickedValue = data
      console.log('data', data)
      console.log('node', node)
    },
    onClickDlgYes() {
      const pickedNodeKey = this.$refs.tree.getCurrentKey()
      const currentNodeData = this.$refs.tree.getCurrentNode()
      if (pickedNodeKey || currentNodeData) {
        this.displayValue = currentNodeData.label
        this.$emit('save', String(pickedNodeKey))
      }
      this.showDialog = false
    },
    onClickDlgNo() {
      this.showDialog = false
    },
  },
}
</script>

<style scoped lang="less">
// /deep/.el-select__input,
// /deep/.el-input__inner {
//   color: transparent;
//   text-shadow: 0 0 black;
// }
</style>
